# 改进的登录接口测试
from httprunner import HttpRunner, Config, Step, RunRequest, Parameters
import allure
import pytest


@allure.epic("管理员登录互帮互助管理系统")
@allure.feature("用户认证模块")
@allure.story("登录接口")
class TestCaseLoginImproved(HttpRunner):

    config = (
        Config("参数化登录测试-改进版")
        .base_url("${read_config()}")
        .variables(**{
            # 定义用例级变量（将被参数化数据覆盖）
            "username": "",
            "password": "",
            "expected_status": 200,
            "user_state": "${get_db_query($username)}",
            "sql_query": "SELECT user_state FROM y_user WHERE username = '${username}'",
            "expected_user_state": "${db_query_all($sql_query)}"
        })
        .verify(False)
        .export(*["token"])
    )

    teststeps = [
        Step(
            RunRequest("密码登录")
            .post("/api/user/login")
            .with_json({
                # 使用统一的${}语法
                "username": "${username}",
                "password": "${password}"
            })
            .extract()
            .with_jmespath("body.token", "token")
            .validate()
            # 使用参数化的期望状态码
            .assert_equal("status_code", 200)
            # 数据库断言
            .assert_equal("body.data.user_state", "$expected_user_state")
            .assert_equal("body.data.user_state", "${get_db_query($username)}")
            .assert_equal("body.data.user_state", "$user_state")
            # 添加条件断言：只有成功时才验证token
            .assert_type_match("body.token", str, "当状态码为200时，token应为字符串")

        )
    ]

    # 参数化配置
    parameters = {
        "username-password-expected_status": "${read_csv(data.csv)}"
    }

    # httprunner集成了pytest参数化。Parameters类：HttpRunner提供的类，负责将配置的parameters转换为pytest可识别的参数化格式.param 参数将接收从CSV读取的每一行数据
    @pytest.mark.parametrize("param", Parameters(parameters))
    def test_start(self, param):
        """
        参数化测试入口
        Args:
            param: 参数化数据，包含username, password, expected_status
        """
        # 添加动态测试标题：使用allure.dynamic.title为每个测试用例动态生成有意义的标题（作区分）。hasattr检查是为了兼容性，防止allure没有dynamic属性时报错
        if hasattr(allure, 'dynamic'):
            allure.dynamic.title(f"登录测试-用户:{param.get('username', 'unknown')}")
        # super().test_start(param)调用HttpRunner的测试执行逻辑.将参数化数据param传递给父类，用于替换config中定义的变量
        super().test_start(param)
        return None  # 显式返回None，或直接不写return语句
